前幾篇介紹了 Electron 如何操作,既然 Electron 是將網頁包起來,那當然可以使用 Vue.js 來做啊!今天就讓我們一起看看該怎麼實作
Electron - 用網頁技術做一個桌面應用程式吧!
Electron - 常用 API 解析
首先我們先使用 Vue CLI
建立一個全新的專案,要使用的套件就選自己需要的
$ npm install -g @vue/cli
$ vue create vue-electron
$ cd vue-electron
再來我們會使用 vue-cli-plugin-electron-builder 這個套件來安裝 Electron,安裝時他會問你安裝版本,沒意外就選最新版本,另外官方這邊推薦使用 yarn 作為套件管理工具
$ vue add electron-builder
這樣就安裝完成了,可以發現 package.json
多了一些指令,而且 src 資料夾內多了一個 background.js
,我們來看看多了什麼東西吧!
// package.json
{
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
// 編譯 Electron
"electron:build": "vue-cli-service electron:build",
// Electron 開發模式
"electron:serve": "vue-cli-service electron:serve",
// 下載 app 依賴,我們用不到
"postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps"
},
// Electron 的進入點
"main": "background.js"
}
// src/background.js
'use strict'
import { app, protocol, BrowserWindow } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const isDevelopment = process.env.NODE_ENV !== 'production'
// 自定義協議
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
async function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
}
})
if (process.env.WEBPACK_DEV_SERVER_URL) {
// 開發者模式載入設定
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
// 正式載入設定
createProtocol('app')
win.loadURL('app://./index.html')
}
}
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
app.on('ready', async () => {
// 開發者模式時載入 Vue 的開發工具
if (isDevelopment && !process.env.IS_TEST) {
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString())
}
}
createWindow()
})
// 開發者模式對應父層事件退出應用程式
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', (data) => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
這邊的 background.js
就是之前的 main.js
,也就是 Electron 的進入點
安裝完成之後還有一些相關的設定需要做,以下一起來看吧~
我們用 router 通常會使用 history 模式,但是在正式環境會導致黑屏,所以官方這邊提供了解決方法如下
// src/router/index.js
const router = new VueRouter({
mode: process.env.IS_ELECTRON ? 'hash' : 'history',
})
建立專案後發現預設沒有 preload.js
,所以這邊我們要自己設定,官方教學在這
// vue.config.js
module.exports = {
pluginOptions: {
electronBuilder: {
preload: 'src/preload.js'
// preload: { preload: 'src/preload.js', preload2: 'src/preload2.js' }
}
}
}
// src/background.js
import path from 'path'
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
preload: path.join(__dirname, 'preload.js')
}
})
最後在 src 資料夾下創建 preload.js 就完成囉!
官方有提到,如果要替換應用程式的 icon,可先將 icon 放到 public
內,然後加入以下設定
// src/background.js
/* global __static */
import path from 'path'
const win = new BrowserWindow({
width: 800,
height: 600,
icon: path.join(__static, 'icon.png'), // 開啟後工具列的 icon
webPreferences: {
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
preload: path.join(__dirname, 'preload.js')
}
})
如果想修改安裝檔的圖片可以使用 electron-icon-builder
$ yarn add --dev electron-icon-builder
// package.json
{
"scripts": {
// --input=圖片位址
"electron:generate-icons": "electron-icon-builder --input=./public/icon.png --output=build --flatten"
}
}
$ yarn electron:generate-icons
執行後就會看到 build/icons
內有各種類型的 icon,之後執行 yarn electron:build
就會看到安裝檔的 icon 換成我們自己的圖示囉!另外也可以直接用下介紹的 vue.config.js
方式做設定
跟編譯相關的幾乎都可以在 vue.config.js
內設定,特別提一下,icon 的部分建議放在 public
資料夾內,並且使用 256*256 以上大小的 ico 檔案,否則會跳錯誤唷
// vue.config.js
module.exports = {
pluginOptions: {
electronBuilder: {
mainProcessFile: 'src/myBackgroundFile.js', // 主進程進入點
rendererProcessFile: 'src/myMainRenderFile.js', // 渲染進程進入點
outputDir: 'electron-builder-output-dir', // 編譯資料夾
preload: 'src/preload.js', // preload 檔案位置
builderOptions: {
asar: false, // 是否使用 asar 壓縮檔案
appId: 'your.id', // 認證的 appId
productName: 'productName', // 專案名稱
artifactName: '${name}.${ext}', // 檔案名稱樣板,有 ESLint 記得關掉
copyright: 'Copyright©ares', // 版權
// Windows 相關設定
win: {
legalTrademarks: 'legalTrademarks', // 商標
icon: 'public/icon.ico', // 安裝檔圖示
target: [{
target: 'nsis', // 檔案類型
arch: ['x64', 'ia32'] // 檔案位元,越多類型檔案越大
}]
},
// DMG 相關設定
dmg: {
icon: 'public/icon.icns' // 安裝檔圖示
},
// Linux 相關設定
linux: {
icon: 'public/icon.png' // 安裝檔圖示
},
// macOS 相關設定
mac: {
icon: 'public/icon.icns' // 安裝檔圖示
},
nsis: {
oneClick: false, // 是否一鍵安裝
perMachine: true, // 是否為每一台機器安裝
installerIcon: 'public/icon.ico', // 安裝圖示
uninstallerIcon: 'public/icon.ico', // 卸載圖示
installerHeaderIcon: 'public/icon.ico', // 安裝頂部圖示
allowToChangeInstallationDirectory: true, // 是否可更改安裝目錄
createDesktopShortcut: true, // 是否建立桌面捷徑
createStartMenuShortcut: true // 是否建立開始捷徑
}
}
}
}
}
詳細可參考以下文件
Vue CLI Plugin Electron Builder
electron-builder
檔案名稱樣板
當設定 allowToChangeInstallationDirectory
為 true
時,預設目錄為 C:\Program Files\專案名
,如果想要修該預設路徑則須在根目錄新增 installer.nsh
,並於 vue.config.js
加上設定
// installer.nsh
!macro preInit
SetRegView 64
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\path"
WriteRegExpandStr HkCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\path"
SetRegView 32
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\path"
WriteRegExpandStr HkCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\Program Files\path"
!macroend
// vue.config.js
module.exports = {
pluginOptions: {
electronBuilder: {
builderOptions: {
nsis: {
allowToChangeInstallationDirectory: true,
include: 'installer.nsh' // 設定檔路徑
}
}
}
}
}
如果同一個專案環境參數不同,想編譯兩個版本的話,Electron 主要是依照 appId
區分應用程式,而我們可以依照環境變數修改設定來達到目的
{
"scripts": {
"electron:build": "vue-cli-service electron:build", // 正式版
"electron:build:dev": "vue-cli-service electron:build --mode development" // 測試版
}
}
// vue.config.js
// 測試版時為 test 字串,正式版則為空
const env = process.env.NODE_ENV === 'development' ? 'test' : ''
module.exports = {
pluginOptions: {
electronBuilder: {
preload: 'src/preload.js',
builderOptions: {
appId: 'your.id' + env, // 測試版時加入字串
productName: 'productName' + env, // 測試版時加入字串
}
}
}
}
這邊使用 electron-updater 來實作更新的功能,他提供使用 Github 、url 或其他的上傳方式,這邊示範一般 url 的寫法
$ yarn add --dev electron-updater
vue.config.js
內加入 publish
的設定module.exports = {
pluginOptions: {
electronBuilder: {
builderOptions: {
publish: [
{
provider: 'generic',
url: ''
}
]
}
}
}
}
加入後打包會產生出一個 latest.yml
,該檔案紀錄了版本資訊,檢查更新會比對這個檔案的版本做更新,將檔案放到伺服器的時候須連同該檔案一起丟上去
// background.js
// 設定更新檔路徑
autoUpdater.setFeedURL({
provider: 'generic', // 亦可使用 Github
url: 'your url'
})
autoUpdater.autoDownload = false // 不自動下載更新檔
// 有更新檔可下載
autoUpdater.on('update-available', info => {
// do something...
})
// 沒有更新檔可下載
autoUpdater.on('update-not-available', info => {
// do something...
})
// 下載進度,開始下載後會持續觸發此事件
autoUpdater.on('download-progress', info => {
console.log(info.percent)
})
// 下載完成
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) => {
autoUpdater.quitAndInstall()
})
// 錯誤
autoUpdater.on('error', function () {
// do something...
})
// 開始下載更新
autoUpdater.checkForUpdates()
因為現在各種套件都整合好了,在 Electron 裡面使用 Vue.js 可說是非常簡單,幾個指令就搞定了,設定也非常的簡單,剩下就是對 Electron 的熟悉度而已~
本魯比對 bradtraversy 的設定檔 跟您的設定檔
有下面 2 處不同
請問您的 .ico 圖示有在 mac 與 linux 環境下打包 & 執行過嗎 ?
之前朋友有跟在下反應過使用 .ico 圖示
打包會有問題 ,
不過本魯沒有 macbook
無法測試
下方分享在下使用的 圖示轉換器
的確在文件裡有寫到要使用 .icns
與 .png
,這邊我真的沒注意到~感謝提醒
(P.S.我也沒有 mac 所以無法測試XD)